/*
 * All header file for c language MUST be include : in extern "C" { }
 */
extern "C" {
#include "../src/uni_timer.c"
}

static int g_count = 0;
static int g_now = 0;

static long long _relative_now_stub(void) {
  g_now += 10;
  return g_now;
}

H2UNIT(timer) {
  void setup() {
    H2STUB(_relative_now, _relative_now_stub);
    TimerInitialize();
    g_count = 0;
    g_now = 0;
  }
  void teardown() {
    TimerFinalize();
  }
};

H2CASE(timer, "add/delete test") {
  Timer *rts[3];
  Timer *rt;
  int i;
  for (i = 0; i < 3; i++) {
    rts[i] = (Timer *)uni_malloc(sizeof(Timer));
  }
  _add_timer(rts[0], 100, TIMER_TYPE_ONESHOOT, NULL, rts[0]);
  _add_timer(rts[1], 200, TIMER_TYPE_ONESHOOT, NULL, rts[1]);
  _add_timer(rts[2], 0, TIMER_TYPE_ONESHOOT, NULL, rts[2]);
  i = 0;
  list_head *p;
  list_for_each(p, &g_timer.timer_list) {
    rt = list_entry(p, Timer, link);
    switch (i) {
      case 0:
        H2EQ_MATH(rts[2], rt);
        H2EQ_MATH(rts[2], rt->arg);
        H2EQ_MATH(30, rt->expire);
        break;
      case 1:
        H2EQ_MATH(rts[0], rt);
        H2EQ_MATH(rts[0], rt->arg);
        H2EQ_MATH(110, rt->expire);
        break;
      case 2:
        H2EQ_MATH(rts[1], rt);
        H2EQ_MATH(rts[1], rt->arg);
        H2EQ_MATH(220, rt->expire);
        break;
      default:
        break;
    }
    i++;
  }
  i = 0;
  _del_timer(rts[1]);
  list_for_each(p, &g_timer.timer_list) {
    rt = list_entry(p, Timer, link);
    switch (i) {
      case 0:
        H2EQ_MATH(rts[2], rt);
        H2EQ_MATH(rts[2], rt->arg);
        H2EQ_MATH(30, rt->expire);
        break;
      case 1:
        H2EQ_MATH(rts[0], rt);
        H2EQ_MATH(rts[0], rt->arg);
        H2EQ_MATH(110, rt->expire);
        break;
      default:
        break;
    }
    i++;
  }
  _free_timer_nodes();
  H2EQ_MATH(0, list_count(&g_timer.timer_list));
}

static void _timer_handler(void *arg) {
  int *count = (int *)arg;
  (*count)++;
}

H2CASE(timer, "manage timer") {
  Timer *rt;
  /* 1. oneshut timer */
  rt = (Timer *)uni_malloc(sizeof(Timer));
  _add_timer(rt, 10, TIMER_TYPE_ONESHOOT, _timer_handler, &g_count);
  _timer_manage();
  H2EQ_MATH(1, g_count);
  /* onshut timer will be deleted after timeup */
  H2EQ_MATH(0, list_count(&g_timer.timer_list));

  /* 2. periodic timer */
  rt = (Timer *)uni_malloc(sizeof(Timer));
  _add_timer(rt, 10, TIMER_TYPE_PERIODICAL, _timer_handler, &g_count);
  _timer_manage();
  H2EQ_MATH(2, g_count);
  /* periodic timer would not be deleted */
  H2EQ_MATH(1, list_count(&g_timer.timer_list));
}
